﻿/*************************************************************************
 * 模块名称:   As标准数学运算算法模块
 * 作者:       姜一
 * 创建时间:   2023年3月
 * 最近修改:   2023年5月23日
 * 描述:       此模块不考虑复杂情况，只提供通用标准的使用内容，不冗余封装。
 * 留言:       此模块由姜一完全开发，如有修改建议或疑问请与作者咨询。
**************************************************************************/
#pragma once
#include "AsMathBasic.h"
#include "AsMathInterval.h"
#include "AsMathLine.h"
#include "AsMathCircle.h"
#include "AsMathRect.h"
#include "AsMathRange3D.h"
#include "AsMathMatrix.h"
#include "AsMathPlane.h"
#include "AsMathGraphics.h"
#include "AsMathSort.h"
#include "AsMath3D.h"

namespace AsMath {

	std::vector<cv::Point> AS_MATH_API calcIntersect(const AsMathCircle& circle, const AsMathLine& line);

};

namespace AsMath {

	// 抽稀
	void AS_MATH_API samplingDown(const std::vector<cv::Point3f>& inputPoints, std::vector<cv::Point3f>& outputPoints, int step);

	// 获取内点
	template <typename _PointsType, typename _GraphicType>
	void getInliers(const _PointsType& inputPoints, const _GraphicType& inputGraphic, _PointsType& outputPoints, const double dist_thresh) {
		_PointsType tmp_points;
		tmp_points.reserve(inputPoints.size() / 2);
		for (const auto& point : inputPoints) {
			if (inputGraphic.calcDistance(point) < dist_thresh) {
				tmp_points.emplace_back(point);
			}
		}
		outputPoints = std::move(tmp_points);
	}

	// 点集仿射变换 (支持多线程并行计算)
	void AS_MATH_API transform(const std::vector<cv::Point3f>& inputPoints, const cv::Mat& inputMatrix, std::vector<cv::Point3f>& outputPoints);

};
/*
	Fit Methods
*/
namespace AsMath {

	// Opencv 直线拟合
	AsMathLine		AS_MATH_API cvFitLine(const std::vector<cv::Point2i>& inputPoints, int distType = cv::DIST_L1, double param = 0.0, double reps = 0.0, double aeps = 0.0);
	AsMathLine		AS_MATH_API cvFitLine(const std::vector<cv::Point2f>& inputPoints, int distType = cv::DIST_L1, double param = 0.0, double reps = 0.0, double aeps = 0.0);

	// Least Squares 最小二乘法 直线拟合
	AsMathLine		AS_MATH_API lsFitLine(const std::vector<cv::Point2i>& inputPoints);
	AsMathLine		AS_MATH_API lsFitLine(const std::vector<cv::Point2f>& inputPoints);

	// Ransac 随机抽样一致性算法 直线拟合
	AsMathLine		AS_MATH_API ransacFitLine(const std::vector<cv::Point2i>& inputPoints, const double dist_thresh, const int skip_thresh = 60);
	AsMathLine		AS_MATH_API ransacFitLine(const std::vector<cv::Point2f>& inputPoints, const double dist_thresh, const int skip_thresh = 60);

	// Ransac 随机抽样一致性算法 直线拟合 固定斜率
	AsMathLine		AS_MATH_API ransacFitKLine(const std::vector<cv::Point2i>& inputPoints, const double k, const double dist_thresh, const int skip_thresh = 60);
	AsMathLine		AS_MATH_API ransacFitKLine(const std::vector<cv::Point2f>& inputPoints, const double k, const double dist_thresh, const int skip_thresh = 60);

	// Principal Component Analysis 主成分分析 直线拟合
	AsMathLine		AS_MATH_API pcaFitLine(const std::vector<cv::Point2i>& inputPoints);
	AsMathLine		AS_MATH_API pcaFitLine(const std::vector<cv::Point2f>& inputPoints);

	// Least Squares 最小二乘法 圆形拟合
	AsMathCircle	AS_MATH_API lsFitCircle(const std::vector<cv::Point2i>& inputPoints);
	AsMathCircle	AS_MATH_API lsFitCircle(const std::vector<cv::Point2f>& inputPoints);

	// Ransac 随机抽样一致性算法 圆形拟合
	AsMathCircle	AS_MATH_API ransacFitCircle(const std::vector<cv::Point2i>& inputPoints, const double dist_thresh, const int skip_thresh = 60);
	AsMathCircle	AS_MATH_API ransacFitCircle(const std::vector<cv::Point2f>& inputPoints, const double dist_thresh, const int skip_thresh = 60);

	// Area 面积法 圆形拟合
	AsMathCircle	AS_MATH_API areaFitCircle(const std::vector<cv::Point2i>& inputPoints);

	// Min Enclosing 最小外包法 圆形拟合
	AsMathCircle	AS_MATH_API meFitCircle(const std::vector<cv::Point2i>& inputPoints);

	// Least Squares 最小二乘法 平面拟合
	AsMathPlane		AS_MATH_API lsFitPlane(const std::vector<cv::Point3f>& inputPointcloud);

	// Ransac 随机抽样一致性算法 平面拟合
	AsMathPlane		AS_MATH_API ransacFitPlane(const std::vector<cv::Point3f>& inputPointcloud, const double dist_thresh, const int skip_thresh = 60);

	// Principal Component Analysis 主成分分析 平面拟合
	AsMathPlane		AS_MATH_API pcaFitPlane(const std::vector<cv::Point3f>& inputPointcloud);

};

namespace AsMath {

	double AS_MATH_API calcStraightness(const std::vector<cv::Point2f>& inputPoints);
	double AS_MATH_API calcStraightness(const std::vector<cv::Point2f>& inputPoints, double keepSlope, double thresh_dist = 1.0);
	double AS_MATH_API calcStraightness(const std::vector<cv::Point2f>& inputPoints, const AsMathLine& inputLine);

	double AS_MATH_API calcInlierRatio(const std::vector<cv::Point2f>& inputPoints, double thresh_dist);
	double AS_MATH_API calcInlierRatio(const std::vector<cv::Point2f>& inputPoints, const AsMathLine& inputLine, double thresh_dist);

	double AS_MATH_API calcPlaneness(const std::vector<cv::Point3f>& inputPoints);

};
/*
	Index(s) Methods
*/
namespace AsMath {

	int AS_MATH_API indexMaxDist(const AsMathLine& inputLine, const std::vector<cv::Point> &inputPoints, const AsMathIntervals& igns = AsMathIntervals());
	int AS_MATH_API indexMaxDist(const AsMathLine& inputLine, const std::vector<cv::Point2f> &inputPoints, const AsMathIntervals& igns = AsMathIntervals());
	int AS_MATH_API indexMaxDist(const AsMathLine& inputLine, const std::vector<cv::Point2d> &inputPoints, const AsMathIntervals& igns = AsMathIntervals());

	std::vector<int> AS_MATH_API indexsNodes(const AsMathLine& inputLine, const std::vector<cv::Point>& inputPolyline, const AsMathIntervals& igns = AsMathIntervals());
	std::vector<int> AS_MATH_API indexsNodes(const AsMathLine& inputLine, const std::vector<cv::Point2f>& inputPolyline, const AsMathIntervals& igns = AsMathIntervals());
	std::vector<int> AS_MATH_API indexsNodes(const AsMathLine& inputLine, const std::vector<cv::Point2d>& inputPolyline, const AsMathIntervals& igns = AsMathIntervals());

	std::vector<int> AS_MATH_API indexsNearbyPoints(const AsMathLine& inputLine, const std::vector<cv::Point>& inputPoints, double dist_thresh, const AsMathIntervals& igns = AsMathIntervals());
	std::vector<int> AS_MATH_API indexsNearbyPoints(const AsMathLine& inputLine, const std::vector<cv::Point2f>& inputPoints, double dist_thresh, const AsMathIntervals& igns = AsMathIntervals());
	std::vector<int> AS_MATH_API indexsNearbyPoints(const AsMathLine& inputLine, const std::vector<cv::Point2d>& inputPoints, double dist_thresh, const AsMathIntervals& igns = AsMathIntervals());

};

